# -*- coding: utf8 -*-
import numpy as np

# 纬度（-88,88) 之间，网格刨分的情况，以及每一级的大小
# 网格剖分以后，各等级网格的大小
geosot_grid_size_list = [(180 * 3600, 88 * 3600), (6 * 3600, 4 * 3600), (30 * 60, 30 * 60), (15 * 60, 10 * 60),
                         (1 * 60, 1 * 60), (4, 4), (2, 2), (1 / 4, 1 / 4), (1 / 32, 1 / 32), (1 / 256, 1 / 256),
                         (1 / 2048, 1 / 2048)]
# 网格剖分以后，各等级网格中网格数量
geosot_grid_number_list = [(1, 1), (60, 22), (12, 8), (2, 3), (15, 10), (15, 15), (2, 2), (8, 8), (8, 8), (8, 8),
                           (8, 8)]


def beidou_grid_encoding_bit_1():
    """
    默认是北半球，按理应该是判断一下纬度在南半球还是北半球
    :return: str
    """
    return 'N'


def beidou_grid_encoding_bit_2_to_4(long_number, lat_number, longitude, latitude):
    """[0,180)"""
    long_number = long_number + 30
    grid_long_str = '0{}'.format(long_number) if long_number < 10 else '{}'.format(long_number)
    grid_lat_str = chr(64 + lat_number)
    return grid_long_str + grid_lat_str


def beidou_grid_encoding_bit_5_to_6(long_number, lat_number, longitude, latitude):
    """[0,x)"""
    long_str = '0123456789AB'
    return long_str[long_number - 1] + '{}'.format(lat_number - 1)


def beidou_grid_encoding_bit_7(long_number, lat_number, longitude, latitude):
    return '{}'.format(long_number - 1 + (lat_number - 1) * 2)


def beidou_grid_encoding_bit_8_to_9(long_number, lat_number, longitude, latitude):
    """[0,x)"""
    long_str = '0123456789ABCDE'
    return long_str[long_number - 1] + '{}'.format(lat_number - 1)


def beidou_grid_encoding_bit_10_to_11(long_number, lat_number, longitude, latitude):
    """[0,x)"""
    long_lat_str = '0123456789ABCDE'
    return long_lat_str[long_number - 1] + long_lat_str[lat_number - 1]


def beidou_grid_encoding_bit_12(long_number, lat_number, longitude, latitude):
    return '{}'.format(long_number - 1 + (lat_number - 1) * 2)


def beidou_grid_encoding_bit_13_to_14(long_number, lat_number, longitude, latitude):
    return '{}{}'.format(long_number - 1, lat_number - 1)


def beidou_grid_encoding_bit_15_to_16(long_number, lat_number, longitude, latitude):
    return beidou_grid_encoding_bit_13_to_14(long_number, lat_number, longitude, latitude)


def beidou_grid_encoding_bit_17_to_18(long_number, lat_number, longitude, latitude):
    return beidou_grid_encoding_bit_13_to_14(long_number, lat_number, longitude, latitude)


def beidou_grid_encoding_bit_19_to_20(long_number, lat_number, longitude, latitude):
    return beidou_grid_encoding_bit_13_to_14(long_number, lat_number, longitude, latitude)


def get_beidou_grid_encoding_bits(longitude, latitude, level_n):
    """
    :param longitude: float  and >zero
    :param latitude: float  and >zero
    :param level_n: int and [0,10]
    :return: str
    """
    if level_n == 0:
        return beidou_grid_encoding_bit_1()
    # 网格大小
    grid_size_level_n_1 = geosot_grid_size_list[level_n - 1]
    grid_size_level_n = geosot_grid_size_list[level_n]
    # 获取 level n-1 层 网格定位角点
    grid_long_level_n_1, grid_lat_level_n_1 = grid_size_level_n_1
    base_point_long = np.floor(longitude / grid_long_level_n_1) * grid_long_level_n_1
    base_point_lat = np.floor(latitude / grid_lat_level_n_1) * grid_lat_level_n_1
    # 获取 level n 层 网格序号
    grid_long_level_n, grid_lat_level_n = grid_size_level_n
    grid_long_number_level_n = int(np.floor((longitude - base_point_long) / grid_long_level_n) + 1)
    grid_lat_number_level_n = int(np.floor((latitude - base_point_lat) / grid_lat_level_n) + 1)
    if level_n == 1:
        return beidou_grid_encoding_bit_2_to_4(grid_long_number_level_n, grid_lat_number_level_n, longitude, latitude)
    elif level_n == 2:
        return beidou_grid_encoding_bit_5_to_6(grid_long_number_level_n, grid_lat_number_level_n, longitude, latitude)
    elif level_n == 3:
        return beidou_grid_encoding_bit_7(grid_long_number_level_n, grid_lat_number_level_n, longitude, latitude)
    elif level_n == 4:
        return beidou_grid_encoding_bit_8_to_9(grid_long_number_level_n, grid_lat_number_level_n, longitude, latitude)
    elif level_n == 5:
        return beidou_grid_encoding_bit_10_to_11(grid_long_number_level_n, grid_lat_number_level_n, longitude, latitude)
    elif level_n == 6:
        return beidou_grid_encoding_bit_12(grid_long_number_level_n, grid_lat_number_level_n, longitude, latitude)
    elif (level_n >= 7) and (level_n <= 10):
        return beidou_grid_encoding_bit_13_to_14(grid_long_number_level_n, grid_lat_number_level_n, longitude, latitude)
    else:
        raise Exception('parameter level -{}- error'.format(level_n))


def beidou_grid_encoding(longitude, latitude, level_n):
    """
    :param longitude: float  and >zero
    :param latitude: float  and >zero
    :param level_n: int and [1,10]
    :return:
    """
    grid_code = ''.join([get_beidou_grid_encoding_bits(longitude, latitude, i) for i in range(level_n + 1)])
    return grid_code


def transform_longitude_latitude(x):
    if x is None:
        raise Exception('parameter: x - {} - is not a valid str'.format(x))
    if isinstance(x, str):
        x = str(x).strip().replace(' ', '')
    x_upper = x.upper()
    flag = x[0]
    x_value = x[1:]
    x_value_list = x_value.split('°')
    if len(x_value_list) == 1:
        d = 0
        x_value_1 = x_value_list[0]
    else:
        d = int(x_value_list[0]) * 3600
        x_value_1 = x_value_list[1]
    x_value_1_list = x_value_1.split('′')
    if len(x_value_1_list) == 1:
        f = 0
        x_value_2 = x_value_1_list[0]
    else:
        f = int(x_value_1_list[0]) * 60
        x_value_2 = x_value_1_list[1]
    x_value_2_list = x_value_2.split('″')
    if len(x_value_2_list) == 1:
        m = 0
    else:
        m = float(x_value_2_list[0])
    if flag in ['N', 'E']:
        return d + f + m
    elif flag in ['S', 'W']:
        return -(d + f + m)
    else:
        raise Exception('parameter:x - {} - is not a valid value'.format(x))


if __name__ == '__main__':
    # 经度 - x 轴 东经
    longitude = 'E116°18′45.37″'
    # 维度 - y 轴 北半球
    latitude = 'N39°59′35.38″'
    # 转化为数值
    longitude_float = transform_longitude_latitude(longitude)
    latitude_float = transform_longitude_latitude(latitude)
    print(f'longitude --{longitude} -- transform into --{longitude_float}--.')
    print(f'latitude --{latitude} -- transform into --{latitude_float}--.')
    for i in range(1, 11, 1):
        result_level_n = beidou_grid_encoding(longitude_float, latitude_float, i)
        print('level i -{}- result is'.format(i), result_level_n)
    # 性能测试
    from timeit import timeit
    iter_number = 1000
    duration = timeit(lambda: beidou_grid_encoding(longitude_float, latitude_float, 10), number=iter_number)
    print('generate grid code,iter number {},cost time is {} seconds'.format(iter_number, duration))
    # generate grid code,iter number 1000,cost time is 0.08302429999457672 seconds